<?php

namespace App\Jobs;

use App\Tables\Region;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Tables\User;
use App\Tables\UserScoreTransferRecord;
use App\Exceptions\OperationException;
use App\Events\BackendNoticeEvent;
use App\Support\Facades\OperationLog;
use DB;

class BackendBatchGiveUserScore implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    private $score;
    private $operation_user_id;
    private $province_code;
    private $city_code;
    private $district_code;

    /**
     * Create a new job instance.
     *
     */
    public function __construct($score, $operation_user_id, $province_code, $city_code, $district_code)
    {
        $this->score = $score;
        $this->operation_user_id = $operation_user_id;
        $this->province_code = $province_code;
        $this->city_code = $city_code;
        $this->district_code = $district_code;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        /**
         * 查询需要批量赠送的用户
         */
        $query = User::general()->where('province_code', $this->province_code);

        if (!empty($this->city_code)) {
            $query = $query->where('city_code', $this->city_code);
        }

        if (!empty($this->district_code)) {
            $query = $query->where('district_code', $this->district_code);
        }

        /**
         * 开始处理赠送积分
         */
        $score = $this->score;
        $user_num = 0;
        $give_total_score = 0;
        foreach ($query->cursor() as $user) {
            DB::transaction(function () use ($user, $score, &$user_num, &$give_total_score) {
                $update_user = User::where('id', $user->id)->lockForUpdate()->first();
                $update_user->score = $update_user->score + $score;
                $res = $update_user->save();
                if (!$res) {
                    throw new OperationException('更新用户积分失败', [$update_user->id, $update_user->name, $score]);
                }

                $user_score_record = new UserScoreTransferRecord();
                $user_score_record->user_id = $update_user->id;
                $user_score_record->order_sn = 'BG' . $update_user->id . date('YmdHis');
                $user_score_record->type = 'backend_give';
                $user_score_record->score = $score;
                $user_score_record->total_score = $update_user->score;
                $res = $user_score_record->save();
                if ($res === false) {
                    throw new OperationException('增加充值赠送积分记录失败', [$update_user->id, $update_user->name, $score]);
                }

                $user_num++;
                $give_total_score += $score;

                // 积分赠送成功后给用户发送通知
                dispatch(new GiveUserScoreNotice($score, $update_user));
            }, 3);
        }

        /**
         * 后台发送通知
         */
        $message = "此次批量赠送积分任务执行完毕。共给了{$user_num}个用户，共送出了{$give_total_score}个积分";
        event(new BackendNoticeEvent($message, $this->operation_user_id));

        /**
         * 记录操作日志
         */
        $operation_user = User::where('id', $this->operation_user_id)->first();

        $regions = Region::whereIn('code', [$this->province_code, $this->city_code, $this->district_code])->get(['name']);
        $region_text = $regions->implode('name', '');

        $log_message = "管理员【{$operation_user->name}】手动给【{$region_text}】区域的用户积分账户增加了{$this->score}个积分。共给了{$user_num}个用户，共送出了{$give_total_score}个积分";
        OperationLog::info('后台批量赠送积分', $log_message);
    }
}
